package com.example.demo.config.jwt;

import java.io.IOException;
import java.io.InputStream;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.bean.User;
import com.example.demo.common.BaseResult;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 登陆时处理数据格式
 * 
 * @author Administrator
 *
 */
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {

	/**
	 * 身份认证管理器，很重要，在config里配置后，注入，不然的自己改身份认证器
	 * <p>
	 * 原本这个在spring security用于校验authentication对象的，也就是校验用户的
	 */
	private AuthenticationManager authenticationManager;

	public JwtLoginFilter(AuthenticationManager authenticationManager) {
		this.authenticationManager = authenticationManager;
	}

	/**
	 * 接收并解析用户凭证
	 */
	@SuppressWarnings("finally")
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {

		// attempt Authentication when Content-Type is json
		if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
				|| request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {

			// use jackson to deserialize json
			ObjectMapper mapper = new ObjectMapper();
			UsernamePasswordAuthenticationToken authRequest = null;
			try (InputStream is = request.getInputStream()) {

				// mapper.readValue(request的请求，带有参数的类.class)
				// 这句相当于request.getParameter(Object.class.getLocal.get其中的对象)
				User authenticationBean = mapper.readValue(is, User.class);

				// 拼接对象
				authRequest = new UsernamePasswordAuthenticationToken(authenticationBean.getUsername(),
						authenticationBean.getPassword());
			} catch (IOException e) {
				e.printStackTrace();
				authRequest = new UsernamePasswordAuthenticationToken("", "");
			} finally {
				setDetails(request, authRequest);
				return this.getAuthenticationManager().authenticate(authRequest);
			}
		}

		// transmit it to UsernamePasswordAuthenticationFilter
		else {
			return super.attemptAuthentication(request, response);
		}
	}

	/**
	 * 登陆成功后
	 */
	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {
		response.setContentType("application/json;charset=UTF-8"); // 响应类型

		// 获取用户信息
		String principal = ((User) authResult.getPrincipal()).getUsername();
		// 生成jwt
		String token = JwtUtils.createToken(principal, false);
		// 返回时，返回用户token
		BaseResult b = new BaseResult(200, "登陆成功", token);

		// 拼接json串
		String jsonString = JSONObject.toJSONString(b);

		response.getWriter().write(jsonString);
	}

	/**
	 * 登陆失败
	 */
	@Override
	protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
			AuthenticationException failed) throws IOException, ServletException {
		response.setContentType("application/json;charset=UTF-8"); // 响应类型
		response.getWriter().write("登陆失败：" + failed.getMessage());
	}
}
